package org.test.jiazi_1.config;

import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.test.jiazi_1.common.exception.BusinessException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理业务异常（最常用）
     */
    @ExceptionHandler(BusinessException.class)
    public SaResult handleBusinessException(BusinessException e) {
        // 业务异常通常不需要打印堆栈，只需记录错误信息
        log.warn("业务异常: [{}] {}", e.getCode(), e.getMessage());

        // 构建统一响应，包含业务异常的错误码和信息
        SaResult result = SaResult.error(e.getMessage())
                .setCode(e.getCode());

        // 如果有附加数据，一并返回
        if (e.getData() != null) {
            result.set("data", e.getData());
        }
        return result;
    }

    /**
     * 处理参数校验异常（如@Valid注解验证失败）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public SaResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        // 提取第一个错误信息返回
        FieldError firstError = bindingResult.getFieldError();
        String errorMsg = firstError != null ? firstError.getDefaultMessage() : "参数校验失败";

        log.warn("参数校验异常: {}", errorMsg);
        return SaResult.error(errorMsg)
                .setCode(400); // 400表示请求参数错误
    }

    /**
     * 处理Sa-Token相关异常（如未登录、权限不足等）
     */
    @ExceptionHandler(SaTokenException.class)
    public SaResult handleSaTokenException(SaTokenException e) {
        log.warn("认证授权异常: {}", e.getMessage());
        // Sa-Token异常通常有特定的错误码，可直接使用
        return SaResult.error(e.getMessage())
                .setCode(401); // 401表示未授权
    }

    /**
     * 处理抽象方法错误（针对之前遇到的问题）
     */
    @ExceptionHandler(AbstractMethodError.class)
    public SaResult handleAbstractMethodError(AbstractMethodError e) {
        log.error("方法实现异常", e); // 这类错误需要详细日志排查
        return SaResult.error("系统组件版本不兼容，请检查依赖")
                .setCode(500);
    }

    /**
     * 处理所有未捕获的异常（兜底处理）
     */
    @ExceptionHandler(Exception.class)
    public SaResult handleException(Exception e) {
        // 未知异常需要详细记录堆栈信息
        log.error("系统异常", e);

        // 生产环境建议不要返回具体异常信息
        String message = "系统异常，请联系管理员";
        // 开发环境可以返回详细信息便于调试
        // String message = e.getMessage() != null ? e.getMessage() : "系统异常，请联系管理员";

        return SaResult.error(message)
                .setCode(500);
    }
}